"""HTTP 客户端封装模块

提供带重试、超时、日志的 HTTP 客户端
"""

import time
import logging
from typing import Dict, Any, Optional, Union, BinaryIO, Tuple
from urllib.parse import urlencode

try:
    import requests
    from requests.adapters import HTTPAdapter
    from urllib3.util.retry import Retry
    _REQUESTS_AVAILABLE = True
except ImportError:
    _REQUESTS_AVAILABLE = False

from ..base.exceptions import NetworkError, CloudStorageError


class HttpClient:
    """HTTP 客户端封装类
    
    提供带重试、超时、日志的 HTTP 客户端功能
    """
    
    def __init__(
        self,
        timeout: int = 30,
        retries: int = 3,
        backoff_factor: float = 0.3,
        status_forcelist: Optional[Tuple[int]] = None,
        session: Optional[requests.Session] = None
    ):
        """初始化 HTTP 客户端
        
        Args:
            timeout: 请求超时时间（秒）
            retries: 重试次数
            backoff_factor: 重试间隔因子
            status_forcelist: 需要重试的状态码列表
            session: 自定义 requests.Session，None 表示创建新会话
            
        Raises:
            ImportError: 如果 requests 库未安装
        """
        if not _REQUESTS_AVAILABLE:
            raise ImportError("requests 库未安装，无法使用 HTTP 客户端。请安装: pip install requests")
        
        self.timeout = timeout
        self.logger = logging.getLogger(__name__)
        
        # 创建或使用提供的会话
        self.session = session or requests.Session()
        
        # 配置重试策略
        if retries > 0:
            retry_strategy = Retry(
                total=retries,
                backoff_factor=backoff_factor,
                status_forcelist=status_forcelist or (500, 502, 503, 504),
                allowed_methods=["HEAD", "GET", "POST", "PUT", "DELETE", "OPTIONS", "TRACE"]
            )
            adapter = HTTPAdapter(max_retries=retry_strategy)
            self.session.mount("http://", adapter)
            self.session.mount("https://", adapter)
        
        # 设置默认请求头
        self.session.headers.update({
            "User-Agent": "clouds-storage-sdk/0.1.0",
            "Accept": "application/json",
            "Accept-Encoding": "gzip, deflate"
        })
    
    def set_default_header(self, name: str, value: str) -> None:
        """设置默认请求头
        
        Args:
            name: 请求头名称
            value: 请求头值
        """
        self.session.headers[name] = value
    
    def set_auth_header(self, token: str, prefix: str = "Bearer") -> None:
        """设置认证头
        
        Args:
            token: 认证令牌
            prefix: 认证前缀，默认为 Bearer
        """
        self.session.headers["Authorization"] = f"{prefix} {token}"
    
    def clear_auth_header(self) -> None:
        """清除认证头"""
        if "Authorization" in self.session.headers:
            del self.session.headers["Authorization"]
    
    def _handle_response(self, response: requests.Response) -> requests.Response:
        """处理响应
        
        Args:
            response: requests.Response 对象
            
        Returns:
            requests.Response: 处理后的响应
            
        Raises:
            NetworkError: 网络错误
            CloudStorageError: 服务器错误
        """
        # 记录请求信息
        self.logger.debug(
            f"HTTP {response.request.method} {response.request.url} -> "
            f"Status: {response.status_code}, Size: {len(response.content)} bytes"
        )
        
        # 检查状态码
        if response.status_code >= 500:
            raise CloudStorageError(
                f"服务器错误: {response.status_code}",
                error_code=str(response.status_code),
                details={"url": response.request.url, "response": response.text[:500]}
            )
        elif response.status_code >= 400:
            raise NetworkError(
                f"客户端错误: {response.status_code}",
                error_code=str(response.status_code),
                details={"url": response.request.url, "response": response.text[:500]}
            )
        
        return response
    
    def get(
        self,
        url: str,
        params: Optional[Dict[str, Any]] = None,
        headers: Optional[Dict[str, str]] = None,
        **kwargs
    ) -> requests.Response:
        """发送 GET 请求
        
        Args:
            url: 请求 URL
            params: 查询参数
            headers: 请求头
            **kwargs: 其他 requests.get 参数
            
        Returns:
            requests.Response: 响应对象
            
        Raises:
            NetworkError: 网络错误
            CloudStorageError: 服务器错误
        """
        try:
            response = self.session.get(
                url,
                params=params,
                headers=headers,
                timeout=self.timeout,
                **kwargs
            )
            return self._handle_response(response)
        except requests.exceptions.RequestException as e:
            raise NetworkError(f"GET 请求失败: {str(e)}")
    
    def post(
        self,
        url: str,
        data: Optional[Union[Dict[str, Any], str, bytes]] = None,
        json: Optional[Dict[str, Any]] = None,
        files: Optional[Dict[str, BinaryIO]] = None,
        headers: Optional[Dict[str, str]] = None,
        **kwargs
    ) -> requests.Response:
        """发送 POST 请求
        
        Args:
            url: 请求 URL
            data: 请求数据
            json: JSON 数据
            files: 上传文件
            headers: 请求头
            **kwargs: 其他 requests.post 参数
            
        Returns:
            requests.Response: 响应对象
            
        Raises:
            NetworkError: 网络错误
            CloudStorageError: 服务器错误
        """
        try:
            response = self.session.post(
                url,
                data=data,
                json=json,
                files=files,
                headers=headers,
                timeout=self.timeout,
                **kwargs
            )
            return self._handle_response(response)
        except requests.exceptions.RequestException as e:
            raise NetworkError(f"POST 请求失败: {str(e)}")
    
    def put(
        self,
        url: str,
        data: Optional[Union[Dict[str, Any], str, bytes]] = None,
        json: Optional[Dict[str, Any]] = None,
        headers: Optional[Dict[str, str]] = None,
        **kwargs
    ) -> requests.Response:
        """发送 PUT 请求
        
        Args:
            url: 请求 URL
            data: 请求数据
            json: JSON 数据
            headers: 请求头
            **kwargs: 其他 requests.put 参数
            
        Returns:
            requests.Response: 响应对象
            
        Raises:
            NetworkError: 网络错误
            CloudStorageError: 服务器错误
        """
        try:
            response = self.session.put(
                url,
                data=data,
                json=json,
                headers=headers,
                timeout=self.timeout,
                **kwargs
            )
            return self._handle_response(response)
        except requests.exceptions.RequestException as e:
            raise NetworkError(f"PUT 请求失败: {str(e)}")
    
    def delete(
        self,
        url: str,
        params: Optional[Dict[str, Any]] = None,
        headers: Optional[Dict[str, str]] = None,
        **kwargs
    ) -> requests.Response:
        """发送 DELETE 请求
        
        Args:
            url: 请求 URL
            params: 查询参数
            headers: 请求头
            **kwargs: 其他 requests.delete 参数
            
        Returns:
            requests.Response: 响应对象
            
        Raises:
            NetworkError: 网络错误
            CloudStorageError: 服务器错误
        """
        try:
            response = self.session.delete(
                url,
                params=params,
                headers=headers,
                timeout=self.timeout,
                **kwargs
            )
            return self._handle_response(response)
        except requests.exceptions.RequestException as e:
            raise NetworkError(f"DELETE 请求失败: {str(e)}")
    
    def download_file(
        self,
        url: str,
        file_path: str,
        chunk_size: int = 8192,
        progress_callback: Optional[callable] = None
    ) -> None:
        """下载文件
        
        Args:
            url: 下载 URL
            file_path: 本地保存路径
            chunk_size: 块大小
            progress_callback: 进度回调函数 (downloaded_bytes, total_bytes)
            
        Raises:
            NetworkError: 网络错误
            CloudStorageError: 服务器错误
        """
        try:
            with self.session.get(url, stream=True, timeout=self.timeout) as response:
                self._handle_response(response)
                
                total_size = int(response.headers.get('content-length', 0))
                downloaded = 0
                
                with open(file_path, 'wb') as f:
                    for chunk in response.iter_content(chunk_size=chunk_size):
                        if chunk:  # 过滤掉保持连接的新块
                            f.write(chunk)
                            downloaded += len(chunk)
                            
                            if progress_callback and total_size > 0:
                                progress_callback(downloaded, total_size)
        except requests.exceptions.RequestException as e:
            raise NetworkError(f"下载文件失败: {str(e)}")
    
    def close(self) -> None:
        """关闭会话"""
        if self.session:
            self.session.close()
    
    def __enter__(self):
        """上下文管理器入口"""
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """上下文管理器出口"""
        self.close()


def is_http_available() -> bool:
    """检查 HTTP 客户端功能是否可用"""
    return _REQUESTS_AVAILABLE